#include "znx_array.h"
#include "znx_string.h"


znx_array_t *
znx_array_create(uint64_t n, size_t size)
{
    if (n < ZNX_ARRAY_MIN_NALLOC) {
        n = ZNX_ARRAY_MIN_NALLOC;
    }

    assert(size > 0);

    znx_array_t *a;
    a = znx_thread_calloc(sizeof(znx_array_t));
    a->nelts = 0;
    a->size = size;
    a->nalloc = n;
    a->elts = znx_thread_calloc(n * size);

    return a;
}


void
znx_array_destroy(znx_array_t *a)
{
    if (a->elts) {
        znx_thread_free(a->elts);
    }
    znx_thread_free(a);
}


void *
znx_array_push(znx_array_t *a)
{
    void        *elt, *new;
    size_t      size;

    /* the array is full */
    if (a->nelts == a->nalloc) {
        /* the a->elts is never null */
        size = a->size * a->nalloc;
        new = znx_thread_calloc(2 * size);
        znx_memcpy(new, a->elts, size);
        znx_thread_free(a->elts);
        a->elts = new;
        a->nalloc *= 2;
    }

    elt = (u_char *) a->elts + a->size * a->nelts;
    a->nelts++;

    return elt;
}


void
znx_array_pop(znx_array_t *a)
{
    /* the array is empty */
    if (a->nelts == 0) {
        return;
    }

    a->nelts--;
}


void
znx_array_remove(znx_array_t *a, uint64_t index)
{
    void    *src, *dst;
    size_t  size;

    /* the array is empty */
    if (a->nelts == 0) {
        return;
    }

    if (index >= a->nelts) {
        return;
    }

    if (index == (a->nelts - 1)) {
        znx_array_pop(a);
        return;
    }

    dst = (u_char *)a->elts + a->size * index;
    src = (u_char *)a->elts + a->size * (index + 1);

    size = a->size * (a->nelts - 1 - index);
    znx_memmove(dst, src, size);

    a->nelts--;
}